// 1 判断该函数是不是被new操作符调用，
// 有的话 this就是 构造函数运行时创建的新对象
//  var f = new foo()

// 2 判断 函数是不是使用显式绑定 call、apply、bind，如果有，
// 那么该函数的this就是 这个三个方法的第一个参数 foo.call(window)

// 3 判断该函数是不是被一个对象的属性引用了地址，
// 该函数有上下文（隐式绑定），
// 在函数执行的时候是通过该对象属性的引用触发，
// 这个函数的this就是当前对象的。 obj.foo();

// 4 上面的三种都没有的话，
// 就是默认绑定，
// 该函数的this就是全局对象或undefined（严格模式下）

; (function () {
    return

    // 函数体内的 this 对象，就是定义时所在的对象，而不是使用时所在的对象。
    global.a = '全局'
    let obj = {
        a: 'a1111',
        b: "bbb111",
        soo: function () {
            console.log(this.a)
            return () => {
                console.log(this.a)
            }
        },
        soo2: function () {
            console.log(this.a)
            return function () {
                console.log(this.a)
            }
        }
    }
    let obj2 = {
        a: "a2222"
    }
    let foo = obj.soo()
    foo() //a1111    // 因为这个是箭头函数所以this在定义时就绑定了上下文的this

    let foo2 = obj.soo2()
    foo2() //全局    // 相当于global.foo2(),这个时候this指向global

    foo.call(obj2) //a1111 改变不了了
    obj.soo.call(obj2) // a2222 显示改变了this指向


})();

// 记住以下四点即可

// 1. this在函数执行时才确认，本质上为函数的实际调用者
// 2. 当没有调用者时，默认调用者为window
// 3. this存储在AO中
// 4. 箭头函数的AO没有this！！！

// 示例代码如下：
let o = {
    fn() {
        console.log(this) // o
        function fn2() { console.log(this) }
        let fn3 = () => console.log(this)
        fn2() // window
        fn3() // o
    },
    fn4: () => console.log(this)
}
o.fn() // o window o
o.fn4() // window

let p = {}
o.fn.call(p) // p window p
o.fn4.call(p) // window

// 我们来分析一下（建议先将上述示例代码截图，对照着看下面的伪代码分析）
// 执行前，先创建全局执行上下文
GloabalEC = {
    VO: {
        this: window
    }
}
// 后续就是调用函数前，创建对应的执行上下文EC
// 执行o.fn()
fnEC = {
    AO: {
        this: o // 这里this为o，因为函数调用者为o
    },
    Scope: [AO, VO] // 查找this时，在自身AO里就查找到了
}
// 执行fn内部的fn2()
fn2EC = {
    AO: {
        this: window // 这里this为window，因为没调用者时，默认函数调用者为window
    },
    Scope: [AO, fnEC.AO, VO] // 查找this时，在自身AO里就查找到了
}
// 执行fn内部的fn3()
fn3EC = {
    AO: {
        // 箭头函数的AO没有this!!!
    },
    Scope: [AO, fnEC.AO, VO] // 查找this，自身AO没有，往上查找发现fnEC.AO有this即o
}

// 执行o.fn4()
fn4EC = {
    AO: {
        // 箭头函数AO无this!!!
    },
    Scope: [AO, VO] // 查找this，自身AO没有，往上查找发现VO即GlobleEC.VO有this，即window
}

// 执行o.fn.call(p)
fnEC = {
    AO: {
        this: p // call函数指定调用者为p
    },
    Scope: [AO, VO] // 查找this，在自身AO找到this为p
}
// 执行fn内部的fn2()
fn2EC = {
    AO: {
        this: window // 这里this为window，因为没调用者时，默认函数调用者为window
    },
    Scope: [AO, fnEC.AO, VO] // 查找this时，在自身AO里就查找到了
}
// 执行fn内部的fn3()
fn3EC = {
    AO: {
        // 箭头函数的AO没有this!!!
    },
    Scope: [AO, fnEC.AO, VO] // 查找this，自身AO没有，往上查找发现fnEC.AO有this即p
}
// 执行o.fn4.call(p)
fn4EC = {
    AO: {
        // 虽然call指定调用者为p，但是箭头函数AO无this，所以call无效！！！
    },
    Scope: [AO, VO] // 自身AO没有this，从GloabelEC.VO找到this为window
}
